package com.framework.bas.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.springframework.orm.hibernate3.HibernateCallback;

import com.framework.bas.dao.IPlmBasDAO;
import com.framework.bas.param.QueryParam;
import com.framework.dbs.dao.IDataBase;
import com.framework.dbs.vo.BaseObject;

@SuppressWarnings("unchecked")
public class PlmBasDAOImpl implements IPlmBasDAO {
	
	private IDataBase dataBase;
	public IDataBase getDataBase() {
		return dataBase;
	}

	public void setDataBase(IDataBase dataBase) {
		this.dataBase = dataBase;
	}

	/**
	 * 平台框架Hibernate对象刷新
	 * @return
	 */
	private void flushHiberate() {
		this.dataBase.getHibernateTemplate().flush();
		this.dataBase.getHibernateTemplate().clear();
	}
	
	/**
	 * 平台框架通过ID查询Hibernate对象
	 * @return
	 */
	public <T extends BaseObject> T queryById(Class<T> clazz,Serializable id) {
		T rs = (T) this.dataBase.findByID_Hibernate_Get(clazz, id);
		this.flushHiberate();
		return rs;
	}
	
	/**
	 * 平台框架Hibernate对象保存
	 * @param BaseObject
	 * @return int
	 */
	public int save(BaseObject object) {
		int rs = this.dataBase.save(object);;
		this.flushHiberate();
		return rs; 
	}

	/**
	 * 平台框架Hibernate对象批量保存
	 * @param List
	 * @return int
	 */
	public <T extends BaseObject> int saveByBatch(List<T> list) {
		int rs = 0;
		for(BaseObject vo : list){
			this.dataBase.save(vo);
			rs++;
		}
		this.flushHiberate();
		return rs;
	}

	/**
	 * 平台框架Hibernate对象更新
	 * @param BaseObject
	 * @return
	 */
	public int update(BaseObject object) {
		int rs = this.dataBase.update(object);
		this.flushHiberate();
		return rs;
	}

	/**
	 * 平台框架Hibernate对象批量更新
	 * @param List
	 * @return int
	 */
	public <T extends BaseObject> int updateByBatch(List<T> list) {
		int rs = 0;
		for(BaseObject vo : list){
			this.dataBase.update(vo);
			rs++;
		}
		this.flushHiberate();
		return rs;
	}
	
	/**
	 * 平台框架Hibernate-NamedQuery更新
	 * @param queryId
	 * @param param
	 * @return int
	 */
	public int updateHiberateByNamedQuery(String queryId,Object[] param) {
		int rs = 0;
		rs = this.dataBase.update_Hibernate_NamedQuery(queryId, param);
		this.flushHiberate();
		return rs;
	}
	
	/**
	 * 平台框架Hibernate对象删除
	 * @param BaseObject
	 * @return int
	 */
	public int delete(BaseObject object) {
		int rs = 0;
		rs = this.dataBase.delete(object);
		this.flushHiberate();
		return rs;
	}
	
	/**
	 * 平台框架Hibernate对象批量删除
	 * @param List
	 * @return
	 */
	public <T extends BaseObject> int deleteByBatch(List<T> list) {
		int rs = 0;
		for(BaseObject vo : list){
			this.dataBase.delete(vo);
			rs++;
		}
		this.flushHiberate();
		return rs;
	}
	
	/**
	 * 通过iBatis进行新建操作。
	 * @param statementId
	 * @param Object[]
	 * @return
	 */
	public int insertIbatisObj(String statementId, Object[] values) {
		return this.dataBase.save_iBatis(statementId, values);
	}

	/**
	 * 通过iBatis进行删除操作。
	 * @param statementId
	 * @param Object[]
	 * @return
	 */
	public int deleteIbatisObj(String statementId, Object[] values) {
		return this.dataBase.delete_iBatis(statementId, values);
	}

	/**
	 * 通过iBatis进行修改操作。
	 * @param statementId
	 * @param Object[]
	 * @return
	 */
	public int updateIbatisObj(String statementId, Object[] values) {
		return this.dataBase.update_iBatis(statementId, values);
	}
	
	/**
	 * 平台框架封装通用查询记录列表
	 * @param QueryParam
	 * @return List
	 */
	public <T> List<T> query(QueryParam qp) {
		List<T> result = null;
		if (qp instanceof QueryParam.EntityPkQueryParam) {
			result = new ArrayList<T>();
			T entity = doQueryEntityPk((QueryParam.EntityPkQueryParam) qp);
			if (entity != null) {
				result.add(entity);
			}
		} else if (qp instanceof QueryParam.EntityQueryParam) {
			result = doQueryEntity((QueryParam.EntityQueryParam) qp);
		} else if (qp instanceof QueryParam.IbatisQueryParam) {
			result = doQueryIbatis((QueryParam.IbatisQueryParam) qp);
		} else if (qp instanceof QueryParam.HqlQueryParamByMap) {
			result = doQueryHqlByMap((QueryParam.HqlQueryParamByMap) qp);
		} else if (qp instanceof QueryParam.HqlQueryParamByArray) {
			result = doQueryHqlByArray((QueryParam.HqlQueryParamByArray) qp);
		} else if (qp instanceof QueryParam.HqlQueryParamByNamedQuery) {
			result = doQueryHqlByNamedQuery((QueryParam.HqlQueryParamByNamedQuery) qp);
		}
		return result;
	}

	/**
	 * 平台框架封装通用查询总记录数
	 * @param QueryParam
	 * @return int
	 */
	public int querySize(QueryParam qp) {
		List result = null;
		if (qp instanceof QueryParam.EntityPkQueryParam) {
			result = new ArrayList();
			Object entity = doQueryEntityPk((QueryParam.EntityPkQueryParam) qp);
			if (entity != null) {
				result.add(entity);
			}
		} else if (qp instanceof QueryParam.EntityQueryParam) {
			result = doQueryEntity((QueryParam.EntityQueryParam) qp);
		} else if (qp instanceof QueryParam.IbatisQueryParam) {
			result = doQueryIbatis((QueryParam.IbatisQueryParam) qp);
		} else if (qp instanceof QueryParam.HqlQueryParamByMap) {
			result = doQueryHqlByMap((QueryParam.HqlQueryParamByMap) qp);
		} else if (qp instanceof QueryParam.HqlQueryParamByArray) {
			result = doQueryHqlByArray((QueryParam.HqlQueryParamByArray) qp);
		} else if (qp instanceof QueryParam.HqlQueryParamByNamedQuery) {
			result = doQueryHqlByNamedQuery((QueryParam.HqlQueryParamByNamedQuery) qp);
		}
		if (result != null && result.get(0) instanceof Long){
			return result==null?0:((Long)(result.get(0))).intValue();
		}else{
			return result==null?0:((Integer)(result.get(0))).intValue();
		}		
	}
	
	/**
	 * 平台框架封装通用单记录查询
	 * @param QueryParam
	 * @return Object
	 */
	public Object queryOne(QueryParam qp) {
		List result = query(qp);
		if(result!=null && result.size()>0){
			return result.get(0);
		}else{
			return null;
		}
	}
	
	protected <T> T doQueryEntityPk(QueryParam.EntityPkQueryParam qp) {
		T result = (T)queryById(qp.getClazz(),qp.getIdentifier());
		this.flushHiberate();
		return result;
	}
	
	protected <T> List<T> doQueryEntity(QueryParam.EntityQueryParam qp) {
		List result = (List<T>)(this.dataBase.getHibernateTemplate().execute(new PlmBasDAOImpl.WrapHiberateComposeCallback(qp)));
		this.flushHiberate();
		return result;
	}
	
	protected <T> List<T> doQueryHqlByMap(final QueryParam.HqlQueryParamByMap qp) {
		List result = (List<T>)(this.dataBase.getHibernateTemplate().execute(new PlmBasDAOImpl.WrapHiberateCallback(qp)));
		this.flushHiberate();
		return result;		
	}
	
	protected <T> List<T> doQueryHqlByArray(final QueryParam.HqlQueryParamByArray qp) {
		List result = (List<T>)(this.dataBase.getHibernateTemplate().execute(new PlmBasDAOImpl.WrapHiberateCallback(qp)));
		this.flushHiberate();
		return result;		
	}
	
	protected <T> List<T> doQueryHqlByNamedQuery(final QueryParam.HqlQueryParamByNamedQuery qp) {
		List result = (List<T>)(this.dataBase.getHibernateTemplate().execute(new PlmBasDAOImpl.WrapHiberateCallback(qp)));
		this.flushHiberate();
		return result;		
	}
	
	protected <T> List<T> doQueryIbatis(final QueryParam.IbatisQueryParam qp) {
		List result = null;
		if (qp.isLimit()){
			result = (List<T>)this.dataBase.find_iBatis(qp.getStatementId(),qp.getQueryValues(),
					qp.getOffset(),qp.getSize());
		}else{
			result = (List<T>)this.dataBase.find_iBatis(qp.getStatementId(),qp.getQueryValues());
		}
		return result;
	}
	
	private static final class WrapHiberateComposeCallback implements HibernateCallback{
		private QueryParam qp;
		public WrapHiberateComposeCallback(QueryParam qp){
			this.qp = qp;
		}

		public Object doInHibernate(org.hibernate.Session session) throws HibernateException, SQLException {
			Criteria criteria = null;
			if (qp instanceof QueryParam.EntityQueryParam){
				QueryParam.EntityQueryParam tmp = (QueryParam.EntityQueryParam)qp;
				criteria = session.createCriteria(tmp.getClazz());
				if(tmp.getQueryOperators()!=null){
					for(int i=0; i<tmp.getQueryOperators().length; i++){
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_EQ)){
							criteria.add(Expression.eq(tmp.getQueryFields()[i], tmp.getQueryValues()[i]));
						}
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_NOTEQ)){
							criteria.add(Expression.ne(tmp.getQueryFields()[i], tmp.getQueryValues()[i]));
						}
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_GT)){
							criteria.add(Expression.gt(tmp.getQueryFields()[i], tmp.getQueryValues()[i]));
						}
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_LT)){
							criteria.add(Expression.lt(tmp.getQueryFields()[i], tmp.getQueryValues()[i]));
						}
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_GTEQ)){
							criteria.add(Expression.ge(tmp.getQueryFields()[i], tmp.getQueryValues()[i]));
						}
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_LTEQ)){
							criteria.add(Expression.le(tmp.getQueryFields()[i], tmp.getQueryValues()[i]));
						}
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_LIKE)){
							criteria.add(Expression.like(tmp.getQueryFields()[i], tmp.getQueryValues()[i]));
						}
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_IN)){
							Object[] objs = new Object[]{null};
							if(tmp.getQueryValues()[i]!=null){
								objs = (Object[])tmp.getQueryValues()[i];
							}
							criteria.add(Expression.in(tmp.getQueryFields()[i], objs));
						}
						if (tmp.getQueryOperators()[i].equals(QueryParam.OP_NOTIN)){
							Object[] objs = new Object[]{null};
							if(tmp.getQueryValues()[i]!=null){
								objs = (Object[])tmp.getQueryValues()[i];
							}
							criteria.add(Expression.not(Expression.in(tmp.getQueryFields()[i], objs)));
						}
					}
				}
				if(StringUtils.isNotBlank(tmp.getOrderBy())){
					String[] orders = tmp.getOrderBy().split(",");
					for(int i=0; i<orders.length; i++){
						String[] orderStr = orders[i].split(" ");
						if(orderStr.length>1){
							if(orderStr[1].equalsIgnoreCase("asc")){
								criteria.addOrder(Order.asc(orderStr[0]));
							}else if(orderStr[1].equalsIgnoreCase("desc")){
								criteria.addOrder(Order.desc(orderStr[0]));
							}
						}else{
							criteria.addOrder(Order.asc(orders[i]));
						}						
					}
				}
				if(StringUtils.isNotBlank(tmp.getGroupBy())){
					criteria.add(Expression.sql(tmp.getGroupBy()));
				}
				if(StringUtils.isNotBlank(tmp.getOtherCause())){
					criteria.add(Expression.sql(tmp.getOtherCause()));
				}
				if (tmp.isLimit()) {
					criteria.setFirstResult(tmp.getOffset());
					criteria.setMaxResults(tmp.getSize());
				}
				return criteria.list();
			}
			return null;
		}
	}
	
	private static final class WrapHiberateCallback implements HibernateCallback{
		private QueryParam qp;
		public WrapHiberateCallback(QueryParam qp){
			this.qp = qp;
		}

		public Object doInHibernate(org.hibernate.Session session) throws HibernateException, SQLException {
			Query query = null;
			if (qp instanceof QueryParam.HqlQueryParamByMap){
				QueryParam.HqlQueryParamByMap tmp = (QueryParam.HqlQueryParamByMap)qp;
				query = session.createQuery(tmp.getQueryHql());
				Map queryValues = tmp.getQueryValues();
				if (queryValues != null && queryValues.size() > 0) {
					Iterator it = queryValues.entrySet().iterator();
					while (it.hasNext()) {
						Map.Entry entry = (Map.Entry) it.next();
						if (entry.getKey() != null&&(entry.getKey() instanceof String)&&((String) entry.getKey()).trim().length() > 0) 
						{
							if (entry.getValue() instanceof List) {
								query.setParameterList((String) entry.getKey(), (List) entry.getValue());
							} else {
								query.setParameter((String) entry.getKey(), entry.getValue());
							}
						}
					}
				}
				if (tmp.isLimit()) {
					query.setFirstResult(tmp.getOffset());
					query.setMaxResults(tmp.getSize());
				}
				return query.list();
			}
			if (qp instanceof QueryParam.HqlQueryParamByArray){
				QueryParam.HqlQueryParamByArray tmp = (QueryParam.HqlQueryParamByArray)qp;
				query = session.createQuery(tmp.getQueryHql());
				Object[] queryValues = tmp.getQueryValues();
				if (queryValues != null && queryValues.length > 0) {
					for (int i = 0; i < queryValues.length; i++) {
						query.setParameter(i, queryValues[i]);
					}
				}
				if (tmp.isLimit()) {
					query.setFirstResult(tmp.getOffset());             
					query.setMaxResults(tmp.getSize());                
				}
				return query.list();
			}
			if (qp instanceof QueryParam.HqlQueryParamByNamedQuery){
				QueryParam.HqlQueryParamByNamedQuery tmp = (QueryParam.HqlQueryParamByNamedQuery)qp;
				query = session.getNamedQuery(tmp.getQueryId());
				Object[] queryValues = tmp.getQueryValues();
				if (queryValues != null && queryValues.length > 0) {
					for (int i = 0; i < queryValues.length; i++) {
						query.setParameter(i, queryValues[i]);
					}
				}
				if (tmp.isLimit()) {
					query.setFirstResult(tmp.getOffset());             
					query.setMaxResults(tmp.getSize());                
				}
				return query.list();
			}
			return null;
		}
	}
	
	/**
	 * 平台框架封装执行存储过程
	 * @param String 过程名称
	 * @param Map 系统参数
	 * @return Map 过程结果
	 */
	public Map runProcedure(String procedureName, Map param) {
		return this.getDataBase().runProcedure_JDBC(procedureName, param);
	}

	public <T> List<T> query(String statementId, Object params) {
		List<T> result = this.dataBase.find_iBatis(statementId,params);
		return result;
	}

	public <T> T queryOne(String statementId, Object params) {
		List<T> result = query(statementId, params);
		if(result!=null && result.size()>0){
			return result.get(0);
		}else{
			return null;
		}
	}

	public int querySize(String statementId, Object params) {
		List result = query(statementId, params);
		if (result != null && result.get(0) instanceof Long){
			return result==null?0:((Long)(result.get(0))).intValue();
		}else{
			return result==null?0:((Integer)(result.get(0))).intValue();
		}		
	}
	
	


}
